import * as vscode from 'vscode';
import { TitleBlock, CalendarBlock, ClassBlock, EventBlock, CommentBlock } from '../blocks';
import fs from 'fs';
import path from 'path';


/**
 * 文档解析方法
 * @param content 文档内容
 */

const DEFAULT_PAGESIZE = 500;

export class DocumentParser {
    // private _blocks: any[] = [];
    private _eventBlocks: EventBlock[] = [];
    private _classBlocks: { [key: string]: ClassBlock } = {};
    private _calendarBlocks: { [key: string]: CalendarBlock } = {};
    private _titleBlock: TitleBlock | null = null;
    private readonly _document: vscode.TextDocument;
    public _docReady = false;
    private _lastModified: number = 0;

    public get docReady() {
        return this._docReady;
    }


    /**
     * 构造函数，初始化文档解析器
     * @remarks 
     * - 仅当当前活动编辑器是SL语言文件时才会初始化
     * - 自动检测并设置当前文档的换行符类型(LF/CRLF)
     */
    constructor(document: vscode.TextDocument) {
        console.log('DocumentParser: 初始化，doc:', document.uri.fsPath);
        this._document = document;
        this._document = document;

        console.log('DocumentParser: 初始化结束，正在加载数据，doc:', document.uri.fsPath);

        this.reload();
    }

    public dispose() {
    }

    public async reload() {
        console.log('DocumentParser: 重新加载，doc:', this._document.uri.fsPath);
        this._lastModified = new Date((await vscode.workspace.fs.stat(this._document.uri)).mtime).getTime();

        this._docReady = false;
        // this._blocks = [];
        this._eventBlocks = [];
        this._classBlocks = {};
        this._calendarBlocks = {};
        this._titleBlock = null;


        await vscode.window.withProgress({
            location: vscode.ProgressLocation.Notification,
            title: '解析文档',
            cancellable: false
        }, async (progress) => {
            await this.parserDocument(progress);
            console.log('DocumentParser: 解析完成，doc:', this._document.uri.fsPath);
        });
        console.log('DocumentParser: 重新加载完成，doc:', this._document.uri.fsPath);
    }

    private async readParts(doc: vscode.TextDocument){
        console.log('DocumentParser: 读取分部文件，doc:', doc.uri.fsPath);
        
        const text = doc.getText();
        const linebreak = doc.eol === vscode.EndOfLine.LF ? '\n' : '\r\n';
        
        // 转换为行
        const lines = text.split(linebreak).map(ln => ln.trim());
        const docDirPath = path.dirname(doc.uri.fsPath);
        const dirSafePath = encodeURIComponent(docDirPath);
        const docPath = doc.uri.fsPath;
        console.log('doc', doc.uri.fsPath);
        console.log('dir', docDirPath);

        const lineResults = [];

        for (let i = 0; i < lines.length; i++) {
            let line = lines[i];

            if (line.startsWith('[cal:') && line.endsWith(']')) {
                // 将dirsafepath 插入到 line 中， 参数名为 d
                line = line.slice(0, line.length - 1) + ' d=' + dirSafePath + ']';
                console.log(line);
            }


            let addLines = [line];
            if (line.startsWith('>')){
                addLines.push(`file=${docPath}`);
            }
            if (line.startsWith('[part:') && line.endsWith(']')) {
                const partfileName = line.substring(6, line.length - 1);
                const partfilePath = path.join(docDirPath, partfileName);
                console.log('part', doc.fileName, line);
                console.log('识别到part:', partfileName , partfilePath);
                if (fs.existsSync(partfilePath)){
                    const partDoc = await vscode.workspace.openTextDocument(partfilePath);
                    addLines = await this.readParts(partDoc);
                }else {
                    addLines = [];
                    vscode.window.showWarningMessage(`未找到分部文件：${partfileName}`);
                }
            }

            if (line.length > 0) {
                lineResults.push(...addLines);
            }
        }
        return lineResults;
    }
    
    private async parserDocument(progress: vscode.Progress<{ message?: string | undefined; increment?: number | undefined; }>) {
        console.log('正在解析文档...');

        const timeStart = Date.now();

        const lines = await this.readParts(this._document);

        console.log('正在构建文档元素...');
        progress.report({ message: '正在构建文档元素...' });
        this.buildBlocks(lines);

        console.log('正在处理事件...');
        progress.report({ message: '正在处理事件...' });
        this.freezeEvents();

        console.log('正在排序事件...');
        progress.report({ message: '正在排序事件...' });
        // 排序所有事件(倒序)
        this._eventBlocks.sort((a, b) => b.time - a.time);

        console.log(`处理完毕，用时 ${(Date.now() - timeStart)}ms`);
        //主动推送事件（找到编辑器光标位置所在的事件块）
        progress.report({ message: `处理完毕，用时 ${(Date.now() - timeStart)}ms` });

        this._docReady = true;
    }


    public async getDefaultData() {
        console.log('DocumentParser: 获取默认数据，doc:', this._document.uri.fsPath);
        let pageIndex = 1;
        let scrollTo = 0;

        if (this._document.uri === vscode.window.activeTextEditor?.document.uri) {
            // 获取光标位置
            const cursor = vscode.window.activeTextEditor.selection.active.line;

            // 获取光标所在事件块
            for (let i = 0; i < this._eventBlocks.length; i++) {
                const block = this._eventBlocks[i];
                if (block.LineStartNumber <= cursor && block.LineEndNumber >= cursor) {
                    // 按照页面Size 判断当前页范围
                    const pageSize = DEFAULT_PAGESIZE;
                    pageIndex = Math.floor(i / pageSize) + 1;
                    scrollTo = i % pageSize;
                    break;
                }
            }
        }

        return await this.getDocument(pageIndex, DEFAULT_PAGESIZE, '', scrollTo);
    }

    //#region 文档解析方法

    /**
     * 冻结所有事件块，防止事件被触发或修改
     * @private 内部实现细节，不对外暴露
     */
    private freezeEvents() {
        for (const block of this._eventBlocks) {
            block.freeze();

            const calendarId = block.timeSystemId;
            if (calendarId === 'system') {
                continue;
            }

            if (calendarId in this._calendarBlocks) {
                const calendar = this._calendarBlocks[calendarId];
                try {
                    block.time = calendar.convert(block.timeText);
                    block.timeSystem = calendar.title;
                } catch (e) {
                    vscode.window.showErrorMessage(`时间转换错误：${block.RawText}`);
                }
            } else {
                vscode.window.showErrorMessage(`未找到日历转换器：${calendarId}`);
            }
        }
    }

    /**
     * 构建文档块结构
     * 
     * 根据输入的行数组解析并构建不同类型的文档块（标题块、日历块、班级块、事件块）
     * 非块类型的行会被附加到当前活动的事件块中（如果存在）
     * 
     * @param lines - 要处理的原始文本行数组
     * @private 内部实现方法
     */
    private buildBlocks(lines: string[]) {

        let currentEventBlock = null;

        for (let i = 0; i < lines.length; i++) {
            const line = lines[i];

            if (CommentBlock.isCommentBlock(line)) {
                // 跳过注释行

            } else if (TitleBlock.isTitleBlock(line)) {
                currentEventBlock = null;
                this._titleBlock = new TitleBlock(line);


            } else if (CalendarBlock.isCalendarBlock(line)) {
                currentEventBlock = null;

                //获取editor当前文档的目录

                const calendarBlock = new CalendarBlock(line);
                this._calendarBlocks[calendarBlock.id] = calendarBlock;


            } else if (ClassBlock.isClassBlock(line)) {
                currentEventBlock = null;
                const classBlock = new ClassBlock(line);
                this._classBlocks[classBlock.id] = classBlock;


            } else if (EventBlock.isEventBlock(line)) {
                currentEventBlock = new EventBlock(line);
                currentEventBlock.LineStartNumber = i + 1;
                this._eventBlocks.push(currentEventBlock);


            } else {
                if (currentEventBlock) {
                    currentEventBlock.addLine(line);
                    currentEventBlock.LineEndNumber = i + 1;
                } else {
                    // 无用的行
                }
            }
        }
    }
    //#endregion

    //#region 搜索事件
    /**
     * 根据时间、组ID、标题和内容搜索事件并返回对应的行号
     * @param time - 事件时间戳
     * @param groupId - 事件所属组ID
     * @param title - 事件标题
     * @param content - 事件内容
     * @returns 匹配事件的行号，未找到时返回-1并显示警告信息
     */
    public searchEvent(time: number, groupId: string, title: string, content: string) {
        console.log('foucsEvent', time, groupId, title, content);
        const evt = this._eventBlocks.find(e => e.time === time && e.groupId === groupId && e.title === title);
        console.log('evt', evt);

        if (evt) {
            const lineNumber = evt.LineStartNumber;
            console.log('lineNumber', lineNumber);
            return {
                docPath: evt.docPath,
                lineNumber
            };

        } else {
            vscode.window.showWarningMessage('未找到事件，请检查事件信息是否发生了变更');
            return {
                lineNumber: -1,
                docPath: ''
            };
        }
    }
    //#endregion

    //#region 获取文档数据
    /**
     * 获取文档数据（分页查询）
     * 
     * @param pageIndex 当前页码（从1开始）
     * @param pageSize 每页显示数量（默认使用DEFAULT_PAGESIZE）
     * @param keywords 搜索关键词（可选）
     * @returns 返回包含文档元数据和事件数据的对象，包括：
     *          - 文档标题、文件名、路径
     *          - 创建时间
     *          - 事件时间范围
     *          - 分组信息
     *          - 分页信息（总数/当前页/总页数）
     *          - 当前页的事件数据
     * 
     * @description 该方法会检查文档最后修改时间，若发现变更会自动重新加载。
     *              支持按关键词过滤事件，并处理未分组事件的默认分类。
     */
    public async getDocument(pageIndex: number, pageSize: number = DEFAULT_PAGESIZE, keywords: string = '', scrollTo: number = 0) {
        console.log('DocumentParser: 获取文档数据，doc:', this._document.uri.fsPath);
        // date
        const createdAt = new Date((await vscode.workspace.fs.stat(this._document.uri)).mtime);
        if (createdAt.getTime() !== this._lastModified) {
            console.log('DocumentParser: 文档已变更，重新加载...');
            this._lastModified = createdAt.getTime();
            await this.reload();
        }

        const titleName = this._titleBlock?.getTitle() || 'Untitled';
        const fileName = path.basename(this._document.fileName);


        // groups
        const groups: { [key: string]: any } = {};
        for (const blockId in this._classBlocks) {
            groups[blockId] = this._classBlocks[blockId].getData();
        }

        // stat
        let events = keywords ?
            this._eventBlocks.filter(e => e.containsKeyword(keywords)) :
            this._eventBlocks;

        // number
        const eventsBeginTime = events[events.length - 1].time;
        const eventsEndTime = events[0].time;


        const total = events.length;
        const _pageSize = DEFAULT_PAGESIZE;
        const _pageCount = Math.ceil(total / _pageSize);
        const _pageIndex = pageIndex < 1 ? 1 : (pageIndex > _pageCount ? _pageCount : pageIndex);


        const skip = (_pageIndex - 1) * _pageSize;
        const take = _pageSize;
        const eventsResult = events.slice(skip, skip + take);

        // 检查是否有事件不含有分组标签
        if (eventsResult.some(e => e.groupId === 'DEFAULT')) {
            groups['DEFAULT'] = { id: 'DEFAULT', title: '未分类' };
        }

        const eventsData = eventsResult.map(e => e.getData());

        const doc = {
            title: titleName,
            fileName,
            filePath: this._document.uri.fsPath,
            createdAt,
            dateRange: {
                begin: eventsBeginTime,
                end: eventsEndTime
            },
            groups,
            eventsCount: total,
            pageIndex: _pageIndex,
            pageSize: _pageSize,
            pageCount: _pageCount,
            events: eventsData,
            scrollTo
        };



        return doc;
    }
    //#endregion
}
